{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e89f490d",
   "metadata": {},
   "source": [
    "# Agents\n",
    "\n",
    "You can pass a Runnable into an agent. Make sure you have `langchainhub` installed: `pip install langchainhub`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "af4381de",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.agents import AgentExecutor, tool\n",
    "from langchain.agents.output_parsers import XMLAgentOutputParser\n",
    "from langchain_community.chat_models import ChatAnthropic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "24cc8134",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ChatAnthropic(model=\"claude-2\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "67c0b0e4",
   "metadata": {},
   "outputs": [],
   "source": [
    "@tool\n",
    "def search(query: str) -> str:\n",
    "    \"\"\"Search things about current events.\"\"\"\n",
    "    return \"32 degrees\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "7203b101",
   "metadata": {},
   "outputs": [],
   "source": [
    "tool_list = [search]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b68e756d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Get the prompt to use - you can modify this!\n",
    "prompt = hub.pull(\"hwchase17/xml-agent-convo\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "61ab3e9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Logic for going from intermediate steps to a string to pass into model\n",
    "# This is pretty tied to the prompt\n",
    "def convert_intermediate_steps(intermediate_steps):\n",
    "    log = \"\"\n",
    "    for action, observation in intermediate_steps:\n",
    "        log += (\n",
    "            f\"<tool>{action.tool}</tool><tool_input>{action.tool_input}\"\n",
    "            f\"</tool_input><observation>{observation}</observation>\"\n",
    "        )\n",
    "    return log\n",
    "\n",
    "\n",
    "# Logic for converting tools to string to go in prompt\n",
    "def convert_tools(tools):\n",
    "    return \"\\n\".join([f\"{tool.name}: {tool.description}\" for tool in tools])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "260f5988",
   "metadata": {},
   "source": [
    "Building an agent from a runnable usually involves a few things:\n",
    "\n",
    "1. Data processing for the intermediate steps. These need to be represented in a way that the language model can recognize them. This should be pretty tightly coupled to the instructions in the prompt\n",
    "\n",
    "2. The prompt itself\n",
    "\n",
    "3. The model, complete with stop tokens if needed\n",
    "\n",
    "4. The output parser - should be in sync with how the prompt specifies things to be formatted."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e92f1d6f",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = (\n",
    "    {\n",
    "        \"input\": lambda x: x[\"input\"],\n",
    "        \"agent_scratchpad\": lambda x: convert_intermediate_steps(\n",
    "            x[\"intermediate_steps\"]\n",
    "        ),\n",
    "    }\n",
    "    | prompt.partial(tools=convert_tools(tool_list))\n",
    "    | model.bind(stop=[\"</tool_input>\", \"</final_answer>\"])\n",
    "    | XMLAgentOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "6ce6ec7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = AgentExecutor(agent=agent, tools=tool_list, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "fb5cb2e3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m <tool>search</tool><tool_input>weather in New York\u001b[0m\u001b[36;1m\u001b[1;3m32 degrees\u001b[0m\u001b[32;1m\u001b[1;3m <tool>search</tool>\n",
      "<tool_input>weather in New York\u001b[0m\u001b[36;1m\u001b[1;3m32 degrees\u001b[0m\u001b[32;1m\u001b[1;3m <final_answer>The weather in New York is 32 degrees\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': 'whats the weather in New york?',\n",
       " 'output': 'The weather in New York is 32 degrees'}"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"whats the weather in New york?\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bce86dd8",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
